

const fs = require("fs");
const path = require("path");

module.exports= async function( dirPath , options  ){
	let files = await getFilesRecursively( dirPath , options.fileExt );

	let changedFiles = await indentFiles( files , options );
	return changedFiles;
};

async function indentFiles(  files , options  ){
	let retFiles = [];
	let charset =  options.charset || "utf8";
	for( let i=0; i< files.length ;i++ ){
		let file =  files[i];
		let changed = await indent( file , charset , options.spaces );
		if( changed )
			retFiles.push( file );
	}
	return retFiles;
}
function testIndentSize( content  ){
	let  line , indentType , allTypes = 0 , prevType=0 ;
	let indentBlanks = [];
	let prevSpaces = "" ;
	let TYPE_TAB = 1 , TYPE_BLANK = 2 ;
	let reg = /\n([ \t]*)[^\s]+/g;
	while( reg.test( content ) ){
		line = RegExp.$1;

		let spaces = RegExp.$1 ;
		if( spaces === prevSpaces ){
			continue;
		}
		if( /^\t+$/.test( spaces ) ){
			indentType = TYPE_TAB;
		}else if( /^ +$/.test( spaces ) ){
			indentType = TYPE_BLANK;

		}else{
			indentType = spaces.length === 0  ?
					(TYPE_TAB & TYPE_BLANK) : 0  ;
		}
		allTypes |= indentType ;

		if(  indentType === TYPE_BLANK || spaces.length ===0 ){
			let indentSize = Math.abs(  spaces.length - prevSpaces.length );
			if( indentSize>0 && indentSize<=8   ) {
				indentBlanks.push(  indentSize );
			}
		}
		prevType   = indentType;
		prevSpaces = spaces;
		if(   indentBlanks.length>=30 )
			break;

	}
	if( allTypes === TYPE_TAB  ){
		return -1 ;
	}
	return parseInt( getPopularValue( indentBlanks ) ) || -1;
}

function getPopularValue( arr ){
	let groupObj = {};

	arr.forEach( item=>{
		groupObj[ item ] = ( groupObj[ item ] || 0 )  + 1 ;
	});
	let selectKey = null , selectValue = 0 ;
	for( let key in groupObj ){

		if(  selectKey === null  || selectValue < groupObj[key] ){
			selectValue = groupObj[ key ] ;
			selectKey = key;
		}
	}
	return selectKey;
}

async function indent(  file , charset , defaultIndentSize ){
	let jsContent = await readFile( file , charset );
	let len  , i , retTab , spaceCount , ch;
	let indentSize = testIndentSize( jsContent );
	if( indentSize === -1 ){
		indentSize = defaultIndentSize;
	}else{
		console.info("文件:" + file +"  indentSize " + indentSize );
	}
	let newContent =  jsContent.replace(/([\n\r])([ \t]+)/g , function( a , $1 ,matchedSpaces ){
		len = matchedSpaces.length;
		retTab = [ $1 ];
		spaceCount = 0;
		for( i = 0 ;i<len;i++ ){
			ch = matchedSpaces.charAt( i );
			if( ch ==='\t' )
				spaceCount = indentSize;
			else
				spaceCount ++;
			if( spaceCount === indentSize){
				spaceCount = 0 ;
				retTab.push( '\t' );
			}
		}
		if( spaceCount>0 ){
			retTab.push( matchedSpaces.substr( len - spaceCount ) );
		}
		return retTab.join("");
	});
	if( newContent !== jsContent ){
		console.info("indent " ,file );
		await writeFile( file  , newContent , charset );
		return true;
	}else{
		console.info( "ignore " , file );
	}
	return false;
}

async function getFilesRecursively( dirPath , fileExt,  jsFiles ){

	if( !jsFiles )
		jsFiles = [];
	let fileExtReg = new RegExp( "\\.(" + fileExt + ")$" , "i" );

	let stats = await getFileStat( dirPath );
	if( fileExtReg.test( dirPath)   && stats.isFile() ){
		jsFiles.push( dirPath  );
		return jsFiles;
	}

	return new Promise( function( resolve ,reject ){

		fs.readdir( dirPath , async function( err ,files ){

			if(err){
				return reject(err);
			}

			for(  let i=0 ; i< files.length ; i++ ){

				let fileName = files[ i ];
				let fullFilePath =  path.join( dirPath ,  fileName );

				let stats = await getFileStat( fullFilePath );
				if( fileExtReg.test( fileName)   && stats.isFile() ){
					jsFiles.push( fullFilePath  );
				}

				if( fileName.indexOf(".") > -1 || fileName.startsWith(".")  ||  fileName==="node_modules" || fileName==="libs" ){
					continue;
				}


				if( stats.isDirectory() ){
					await getFilesRecursively( fullFilePath  ,fileExt, jsFiles );
				}


			}
			resolve( jsFiles );

		});

	})
}

function readFile(  file , options ){
	return new Promise( function( resolve ,reject ){
		fs.readFile( file , options , function( err , result ){
			if( err )
				reject( err );
			else
				resolve( result );
		} );
	});
}
function writeFile(  file , data , options ){
	return new Promise( function( resolve ,reject ){
		fs.writeFile( file , data , options , function( err , result ){
			if( err )
				reject( err );
			else
				resolve( result );
		} );
	});
}
function getFileStat( filePath ){
	return new Promise( function( resolve ,reject ){
		fs.stat( filePath , function( err, stats ){
			if( err)
				reject( err );
			else
				resolve( stats );
		});
	});
}
